//============================================================================
// Name        : FileComparisor.cpp
// Author      : Jeff
// Version     :
// Copyright   : Wang
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <json/json.h>

#include <string.h>
#include <time.h>

#include <src/RawFileComparisor.h>
#include <src/FileComparisor.h>
#include <hash/md5.h>
#include <src/FileReader.h>

using namespace fs;

char* getTime(char* buffer)
{
	memset(buffer, 0, sizeof(buffer));
	time_t rawtime;
	struct tm * timeinfo;

	time (&rawtime);
	timeinfo = localtime (&rawtime);

	strftime (buffer,80,"%d-%m-%Y,%H:%M:%S",timeinfo);

	return buffer;
}


void testBufferCmpForEndDiff()
{
	Comparisor* pComparisor = new Comparisor();

	// Check diff at end.
	char left[] = "1234567890000000000";
	char right[] = "1234567891111";

	Json::Value result;
	pComparisor->chunk_size = 5;
	pComparisor->diff(left, sizeof(left), right, sizeof(right), &result);
	std::cout << result.toStyledString() << std::endl;

	delete pComparisor;
}

void testBufferCmpForBeginDiff()
{
	Comparisor* pComparisor = new Comparisor();

	// Check diff at end.
	std::string left = "0001234567890000";
	std::string right = "11111234567891111";

	Json::Value result;
	pComparisor->chunk_size = 5;
	pComparisor->diff(left.c_str(), left.length(), right.c_str(), right.length(), &result);
	std::cout << result.toStyledString() << std::endl;

	delete pComparisor;
}

void testBufferCmpForMidDiff()
{
	Comparisor* pComparisor = new Comparisor();

	// Check diff at end.
	std::string left = "1934567890";
	std::string right = "1234567890";

	Json::Value result;

	// When if block == 1
	pComparisor->chunk_size = 1;
	pComparisor->diff(left.c_str(), left.length(), right.c_str(), right.length(), &result);
	std::cout << result.toStyledString() << std::endl;

	result.clear();
	// When block size == 32
	pComparisor->chunk_size = 32;
	pComparisor->diff(left.c_str(), left.length(), right.c_str(), right.length(), &result);
	std::cout << result.toStyledString() << std::endl;

	delete pComparisor;
}

void testEndDiff()
{
	Comparisor* pComparisor = new Comparisor();

	// Check diff at end.
	char left[] = "1234567890000000000";
	char right[] = "1234567891111";

	Json::Value result;
	pComparisor->chunk_size = 5;
	pComparisor->diff(left, sizeof(left), right, sizeof(right), &result);
	std::cout << result.toStyledString() << std::endl;

	delete pComparisor;
}


void testDiff()
{
	Comparisor* pComparisor = new Comparisor();

	// Check diff at end.
	char left[] = "000123456789abcdefghij";
	char right[] = "1234511167891111";

	Json::Value result;
	pComparisor->chunk_size = 3;
	pComparisor->diff(left,  sizeof(left), right, sizeof(right), &result);
	std::cout << result.toStyledString() << std::endl;

	delete pComparisor;
}

void testRawFileComparisor(const char* left, const char* right, const char* out_file)
{
	char buffer[80] = "\0";
	std::cout << "Test start:\t" << getTime(buffer) << std::endl;

	std::fstream fs_json;
	RawFileComparisor* pComparisor = new RawFileComparisor();
	//pComparisor->block_size = 1024;
	pComparisor->setLeft(left);
	pComparisor->setRight((NULL==right)?"":right);
	Json::Value diff = pComparisor->compare();
	std::cout << diff.toStyledString() << std::endl;
	delete pComparisor;

	fs_json.open(out_file, std::ios::out | std::ios::trunc);
	fs_json.write(diff.toStyledString().c_str(), diff.toStyledString().length());
	fs_json.close();

	std::cout << "Test end:\t" << getTime(buffer) << std::endl;
}

void testMD5Update()
{
	MD5 md5;
	md5.Init();
	md5.Update((unsigned char*)"abcdec", 6);
	md5.Final();
	std::cout << md5.digestChars << std::endl;

	md5.Init();
	md5.Update((unsigned char*)"abc", 3);
	md5.Update((unsigned char*)"dec", 3);
	md5.Update((unsigned char*)"", 0);
	md5.Final();
	std::cout << md5.digestChars << std::endl;
}

void testMD5File(const char* file)
{
	MD5 md5;
	std::cout << md5.digestFile((char*)file) << std::endl;
}

void testFileReader(std::string json_file)
{
	std::fstream json_stream;
	json_stream.open(json_file.c_str(), std::ios::in);

	Json::Value json;
	Json::Reader reader;
	reader.parse(json_stream, json, false);

	FileReader* fileReader = new FileReader(json);

	MD5 md5;
	md5.Init();
	char buffer[1000];
	int c=fileReader->read(buffer, sizeof(buffer));
	while(0 != c)
	{
		md5.Update((unsigned char*)buffer, c);
		c=fileReader->read(buffer, sizeof(buffer));
	}

	md5.Final();
	std::cout << md5.digestChars << std::endl;
}

void testFileComparisor(const char* left, const char* right, const char* out_file)
{
	try
	{
		FileComparisor fileComparisor;
		fileComparisor.setLeft(left);
		fileComparisor.setRight(right);
		//fileComparisor.block_size = 1024;
		Json::Value diff = fileComparisor.compare();
		std::cout << diff.toStyledString() << std::endl;

		std::fstream fs_json;
		fs_json.open(out_file, std::ios::out | std::ios::trunc);
		fs_json.write(diff.toStyledString().c_str(), diff.toStyledString().length());
		fs_json.close();
	}
	catch(std::exception & e)
	{
		std::cout << e.what() << std::endl;
	}
}

//#define TEST_MD5
#define TEST_BUFFER_COMPARISOR
#define TEST_RAW_FILE_COMPARISOR
#define TEST_FILEREADER
#define TEST_FILE_COMPARISOR

int main(int argc, const char* argv[])
{
#ifdef TEST_BUFFER_COMPARISOR
	testBufferCmpForEndDiff();
	testBufferCmpForBeginDiff();
	testBufferCmpForMidDiff();

	testEndDiff();
	testDiff();
#endif

#ifdef TEST_RAW_FILE_COMPARISOR
	testRawFileComparisor(argv[1], argv[2], "test12.json");
	testRawFileComparisor(argv[2], argv[1], "test21.json");
#endif

#ifdef TEST_MD5
	testMD5Update();
	testMD5File(argv[1]);
#endif

#ifdef TEST_FILEREADER
	// Calculate MD5
	testMD5File(argv[1]);
	// Calculate split file MD5
	testFileReader("test12.json");

	// Calculate MD5
	testMD5File(argv[2]);
	// Calculate split file MD5
	testFileReader("test21.json");
#endif

#ifdef TEST_FILE_COMPARISOR
	// Compare test2.dat to test1.dat.json
	testFileComparisor(argv[2], "test12.json", "test2_12.json");
	testMD5File(argv[2]);
	testFileReader("test21.json");
	testFileReader("test2_12.json");

	testFileComparisor(argv[1], "test21.json", "test1_21.json");
	testMD5File(argv[1]);
	testFileReader("test12.json");
	testFileReader("test1_21.json");
#endif

	return 0;
}
